package org.abac4j.evaluation;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.abac4j.annotations.Rule;
import org.abac4j.context.AbacContext;
import org.abac4j.context.PostProcessor;
import org.abac4j.domain.AnnotatedEffect;
import org.abac4j.el.ExpressionLanguageService;
import org.abac4j.el.JbossELService;
import org.jboss.el.lang.EvaluationContext;

public class AbacELAnnotationEvaluator implements AbacEvalutatorService {
	
	public Object evaluate(AbacContext context, Object object, Method method, Object[] args) throws Exception {
		ExpressionLanguageService elService = new JbossELService();
		context.getAttributeRepository().addAttributeMap(this.getVariableMap(args));
		EvaluationContext elContext = elService.buildEvaluationContext(
				context.getMethodRepository().getFunctionMethodMap(), 
				context.getAttributeRepository().getAttributeMap());
		
		Rule rule = method.getAnnotation(Rule.class);
		
		AnnotatedEffect annotatedEffect = rule.effect();
		if (!elService.evaluateBooleanExpression(elContext, rule.condition())
				|| (annotatedEffect.equals(AnnotatedEffect.DENY_EXECUTION))){
			throw new RuntimeException("Denied Exception");
		}
		
		Object returnObj = method.invoke(object, args);
	
		if (annotatedEffect.equals(AnnotatedEffect.POST_PROCESS)) {
			Class<? extends PostProcessor> clazz = rule.postProcessor();
			Method m = clazz.getDeclaredMethod("postProcess", Object[].class);
			returnObj = m.invoke(clazz.newInstance(), new Object[] { new Object[] { returnObj, args } });
		}
		return returnObj;
	}
	
	private Map<String, Object> getVariableMap(Object[] args) {
		Map<String, Object> argsMap = new HashMap<String, Object>();
		int counter = 0;
		for (Object obj : args) {
			argsMap.put("arg" + counter++, obj);
		}
		return argsMap;
	}
}